package org.dromara.web.service.impl;

import cn.dev33.satoken.stp.SaLoginModel;
import cn.hutool.core.util.ObjectUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.dromara.common.core.constant.Constants;
import org.dromara.common.core.constant.GlobalConstants;
import org.dromara.common.core.constant.GrantTypeConstants;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.domain.model.WxSmsLoginBody;
import org.dromara.common.core.enums.LoginType;
import org.dromara.common.core.exception.user.CaptchaExpireException;
import org.dromara.common.core.exception.user.UserException;
import org.dromara.common.core.utils.MessageUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.satoken.utils.LoginUserHelper;
import org.dromara.common.satoken.utils.MultipleStpUtil;
import org.dromara.common.tenant.annotation.IgnoreTenant;
import org.dromara.system.domain.SysClient;
import org.dromara.system.mapper.SysUserMapper;
import org.dromara.web.domain.vo.LoginVo;
import org.dromara.web.service.IAuthStrategy;
import org.dromara.web.service.WxLoginService;
import org.dromara.wx.domain.bo.WxUserBo;
import org.dromara.wx.domain.vo.WxUserVo;
import org.dromara.wx.service.IWxUserService;
import org.springframework.stereotype.Service;

/**
 * 短信认证策略
 *
 * @author Michelle.Chung
 */
@Slf4j
@Service(GrantTypeConstants.WX_SMS + IAuthStrategy.BASE_NAME)
@RequiredArgsConstructor
public class WxSmsAuthStrategy implements IAuthStrategy<WxSmsLoginBody> {
    private final WxLoginService wxLoginService;
    private final IWxUserService IWxUserService;

    //TODO 待修改成不返回LoginVo 而是修改登录用户权限
    @Override
    @IgnoreTenant
    public LoginVo login(WxSmsLoginBody loginBody, SysClient client) {
        String phoneNumber = loginBody.getPhonenumber();
        String smsCode = loginBody.getSmsCode();
        String clientId = client.getClientId();
        Integer wxuserId = loginBody.getWxuserId();

        // SAIL 验证短信验证码
        //wxLoginService.checkLogin(LoginType.SMS, phoneNumber, () -> !validateSmsCode( phoneNumber, smsCode));

        // 通过手机号查找用户，绑定用户
        WxUserVo user = loadUserByPhonenumber(phoneNumber,wxuserId);

        // 此处可根据登录用户的数据不同
        LoginUser loginUser = wxLoginService.buildWxLoginUser(user);
        loginUser.setClientKey(client.getClientKey());
        loginUser.setDeviceType(client.getDeviceType());

        // SAIL 删除model设置tocken过期时间。原因：xcx登录是无感登录
        // 生成token
        // TODO 改回user，注意controller.crud的add
        LoginHelper.login(loginUser,null);

        LoginVo loginVo = new LoginVo();
        loginVo.setAccessToken(MultipleStpUtil.SYSTEM.getTokenValue());
        loginVo.setExpireIn(ObjectUtil.defaultIfNull(client.getTimeout(), MultipleStpUtil.SYSTEM.getTokenTimeout()));
        loginVo.setClientId(clientId);
        return loginVo;
    }

    /**
     * 校验短信验证码
     */
    private boolean validateSmsCode( String phonenumber, String smsCode) {
        String code = RedisUtils.getObject(GlobalConstants.CAPTCHA_CODE_KEY + phonenumber);
        if (StringUtils.isBlank(code)) {
            wxLoginService.recordLogininfor(phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
            throw new CaptchaExpireException();
        }
        return code.equals(smsCode);
    }

    private WxUserVo loadUserByPhonenumber(String phonenumber, Integer wxuserId) {

        WxUserVo wxUserVo = IWxUserService.selectWxUserByPhonenumber(phonenumber);
        if(ObjectUtils.isEmpty(wxUserVo)){
            log.info("该用户信息未绑定电话号 phonenumber：{}", phonenumber);
            Boolean update = IWxUserService.updateByBo(WxUserBo.WxUserBoBuilder.aXhljWxUserBo()
                .withId(wxuserId)
                .withPhoneNumber(phonenumber)
                .build());
            if(update){
                log.info("微信用户绑定电话成功");
            }else {
                throw new UserException("微信用户绑定电话失败");
            }
        }
        return wxUserVo;
    }
}
